package main

import (
	"context"
	"fmt"
	"gin-minio/config"
	"github.com/gin-gonic/gin"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"log"
	"net/http"
	"path/filepath"
	"strings"
)

var minioClient *minio.Client
var bucketName string //你的存储桶名称

func initMinIO() {
	config.LoadConfig(".env")
	// 初始化 MinIO 客户端
	endpoint := config.Config.Endpoint
	accessKeyID := config.Config.AccessKey
	secretAccessKey := config.Config.SecretKey

	bucketName = config.Config.Bucket
	useSSL := false
	var err error

	minioClient, err = minio.New(endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
		Secure: useSSL,
	})

	if err != nil {
		log.Fatalln(err)
	}

	// 检查存储桶是否存在，不存在则创建
	ctx := context.Background()
	exists, err := minioClient.BucketExists(ctx, bucketName)
	if err != nil {
		log.Fatalln(err)
	}
	if !exists {
		err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})
		if err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Bucket %s created successfully\n", bucketName)
	}
}
func main() {
	// 初始化 MinIO 客户端
	initMinIO()
	router := gin.Default()

	router.POST("/upload", uploadFile)
	router.POST("/upload-location/:bucket/:location", uploadFileWithLocation)

	router.GET("/files", listFiles)

	// 下载文件
	router.GET("/download/:filename", downloadFile)
	router.DELETE("/files/:filename", deleteFile)

	// 启动服务器
	fmt.Println("Server is running on http://localhost:8080")
	router.Run(":8080")
}

// 下载文件
func downloadFile(c *gin.Context) {
	filename := strings.TrimSpace(c.Param("filename"))
	if filename == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Filename is required"})
		return
	}
	fmt.Println("filename", filename)
	ctx := context.Background()
	// 获取文件信息
	objectInfo, err := minioClient.StatObject(ctx, bucketName, filename, minio.StatObjectOptions{})
	if err != nil {

		c.JSON(http.StatusInternalServerError, gin.H{"error": "get stat file not found" + filename + err.Error()})
		return
	}
	// 获取文件内容
	object, err := minioClient.GetObject(ctx, bucketName, filename, minio.GetObjectOptions{})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": " file not found" + filename + err.Error()})
		return
	}
	defer object.Close()
	// 设置响应头
	extraHeaders := map[string]string{
		"Content-Disposition": fmt.Sprintf(`attachment; filename="%s"`, filename),
	}
	c.DataFromReader(http.StatusOK, objectInfo.Size, "application/octet-stream", object, extraHeaders)
}

func deleteFile(c *gin.Context) {
	filename := c.Param("filename")
	ctx := context.Background()
	err := minioClient.RemoveObject(ctx, bucketName, filename, minio.RemoveObjectOptions{})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "file not found"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "File deleted successfully"})
}

func listFiles(c *gin.Context) {
	ctx := context.Background()
	// 获取存储桶中的对象列表
	objectCh := minioClient.ListObjects(ctx, bucketName, minio.ListObjectsOptions{
		Recursive: true,
	})
	var files []string
	for object := range objectCh {
		if object.Err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": object.Err.Error()})
		}

		files = append(files, object.Key)

	}
	c.JSON(http.StatusOK, gin.H{"files": files})
}

func uploadFileWithLocation(c *gin.Context) {

	bucketName := c.Param("bucket")
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	// 打开上传的文件
	fileReader, err := file.Open()
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	defer fileReader.Close()

	location := c.PostForm("location")
	err = minioClient.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{
		Region: location,
	})
	if err != nil {
		exists, errBucketExists := minioClient.BucketExists(context.Background(), bucketName)
		if errBucketExists == nil && exists {
			msgO := fmt.Sprintf("The bucket %s already exists\n", bucketName)
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error() + msgO})
			return
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"errBucketExists not nil error": err.Error()})
			return
		}
		return
	}

	// upload files
	// 上传到 MinIO
	ctx := context.Background()
	objectName := filepath.Base(file.Filename)
	contentType := file.Header.Get("Content-Type")

	_, err = minioClient.PutObject(ctx, bucketName, objectName, fileReader, file.Size, minio.PutObjectOptions{ContentType: contentType})
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "File uploaded successfully"})
}

// 上传文件
func uploadFile(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	// 打开上传的文件
	fileReader, err := file.Open()
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	defer fileReader.Close()

	// 上传到 MinIO
	ctx := context.Background()
	objectName := filepath.Base(file.Filename)
	contentType := file.Header.Get("Content-Type")

	_, err = minioClient.PutObject(ctx, bucketName, objectName, fileReader, file.Size, minio.PutObjectOptions{ContentType: contentType})
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "File uploaded successfully"})

}
